﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Rbac.Share.Utils;
using Rbac.Contracts.DTO.OutPut;
using Rbac.Server;
using Rbac.Contracts.DTO.InPut;
using Rbac.Contracts.Interface;
using Microsoft.AspNetCore.Mvc.Authorization;

namespace Rbac.API.Filters
{
	/// <summary>
	/// Token 自动刷新
	/// </summary>
	public class TokenActionFilter : IActionFilter
	{
		private readonly TokenService _tokenService;
		private readonly JwtTokenOption _jwtTokenOption;
		private readonly IPermissionServer _permissionServer;

		public TokenActionFilter(TokenService tokenService, IOptionsMonitor<JwtTokenOption> monitor, IPermissionServer permissionServer)
		{
			_tokenService = tokenService;
			_jwtTokenOption = monitor.CurrentValue;
			_permissionServer = permissionServer;
		}
		/// <summary>
		/// 行为之前
		/// </summary>
		/// <param name="context"></param>

		public void OnActionExecuting(ActionExecutingContext context)
		{
			if(HasAllowAnonymous(context))
			{
				return;
			}
			var controllerName = context.RouteData.Values["controller"].ToString();
			var actionName = context.RouteData.Values["action"].ToString();
			//判断是否有权限
			var result =_permissionServer.Haspermission(new HasPermissionInput
			{
				ControllerName = controllerName,
				ActionName = actionName,
		
			});
			if(!result)
			{
				context.Result = new ForbidResult();
			}
		}
		/// <summary>
		/// 行为之后
		/// </summary>
		/// <param name="context"></param>

		public void OnActionExecuted(ActionExecutedContext context)
		{
			// 只对需要认证授权的方法刷新token
			if (!HasIAuthorize(context))
			{
				return;
			}
			if (context.HttpContext.User.Identity is { IsAuthenticated: true })
			{
				var objectResult = context.Result as ObjectResult;
				var val = objectResult?.Value;
				if (val == null)
				{
					return;
				}
				var type = objectResult!.DeclaredType; // 实际返回的类型

				var userClaims = context.HttpContext.User.Claims.ToList();
				// 到期时间
				var exp = Convert.ToInt64(userClaims.FirstOrDefault(p => p.Type == "exp")!.Value);

				// 判断token 是否过期: 拿到期时间-当前过期 = token 剩余可用时间
				var timeSpan = Share.Utils.DateTimeUtil.GetDataTime(exp).Subtract(DateTime.Now);
				// 剩余的时间
				var minutes = timeSpan.TotalMinutes;

				// 如果剩余时间少于Token有效时间的一半，我们返回一个新的Token给前端
				if (minutes < _jwtTokenOption.TokenExpireTime / 2.0)
				{
					var token = _tokenService.GenerateToken(new UserOutPut
					{
						NickName = userClaims.FirstOrDefault(p => p.Type == "NickName")!.Value,
						UserName = userClaims.FirstOrDefault(p => p.Type == "UserName")!.Value,
						//RoleName = userClaims.FirstOrDefault(p => p.Type == "RoleName")!.Value,
						//RoleId = Convert.ToInt32(userClaims.FirstOrDefault(p => p.Type == "RoleId")!.Value),
						UserId = Convert.ToInt32(userClaims.FirstOrDefault(p => p.Type == "UserId")!.Value)
					});
					// 设置新的token，给前端重新存储
					type!.GetProperty("Token")!.SetValue(val, token);
					context.Result = new JsonResult(val);
				}
			}
		}

		// 判断是否含有Authorize
		private bool HasIAuthorize(ActionExecutedContext context)
		{
			if (context.Filters.Any(filter => filter is IAuthorizationFilter))
			{
				return true;
			}
			// 终节点：里面包含了路由方法的所有元素信息（特性等信息）
			var endpoint = context.HttpContext.GetEndpoint();
			return endpoint?.Metadata.GetMetadata<IAuthorizeData>() != null;
		}
		// 判断是否含有IAllowAnonymous
		private bool HasAllowAnonymous(ActionExecutingContext context)
		{
			if (context.Filters.Any(filter => filter is IAllowAnonymousFilter))
			{
				return true;
			}
			// 终节点：里面包含了路由方法的所有元素信息（特性等信息）
			var endpoint = context.HttpContext.GetEndpoint();
			return endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null;
		}
	}
}
